# Declarative Animation

Declarative animation is a big topic. We'll scratch the surface here.

## The declarative animation loop

One way you can achieve an animation with `react-babylonjs` is by using the
Engine render loop, which runs many times per second. You can receive callbacks
for this loop by using the `useBeforeRender` hook. As its name implies, it is
called before each frame render and allows you to make any changes needed to
simulate animations.

The beauty of Component based design is that each React component can register
their own animation loop handler and take responsibility just for its small
task.

Here's some basic usage:

```tsx
const scene = useScene()

useBeforeRender(() => {
  if (scene) {
    // This gets called ~60 FPS or whatever your frame rate is.
    // Don't do a lot in here, just essentials
  }
})
```

## Degrees of Freedom

Every object in 3D has a _position_ (x, y, z) in space and a _rotation_ (roll,
pitch, yaw). As
[google states it](https://developers.google.com/vr/discover/degrees-of-freedom):

> Rotational movement is relative to the x, y, and z axes, commonly termed
> pitch, yaw, and roll. The position corresponds to translational movement along
> those axes, which can be thought of as moving forward or backward, moving left
> or right, and moving up or down.

You can read a lot about this elsewhere, so we won't cover it in much depth
here. The main point to take away is that animation involves affecting one or
more of these degrees of freedom on each object (animations can also be for
colors, brightness, etc.).

Let's try `useBeforeRender` to adjust these properties.

## Creating the famous rotating box

Using a box as an example - we will rotate it about the Y axis, known as _yaw_.
And, we'll do it many times per second.

Here's how to make a box (`<box ... />` (recall from previous guide how it uses
the Babylon.js
[CreateBox](https://doc.babylonjs.com/typedoc/modules/BABYLON#CreateBox-2)). We
need to make sure we are passing required constructor (or factory method)
arguments.

- Only `name` is required - the `Scene` object will be passed for you
  automatically.
- Properties of the returned object of type `Mesh` can be set as well (ie:
  `position`, `rotation`). Changes to those properties will flow to the
  underling mesh - just like changing a DOM element attribute works.

```tsx
<box name="box" size={2} position={new Vector3(0, 1, 0)} />
```

<code src="./animation/LoneBox.tsx" />

Now to make it spin. We will make the box spin about the Y axis. From
[Mesh rotation in Babylon](https://doc.babylonjs.com/divingDeeper/mesh/transforms/center_origin/rotation)
we see that the Y axis is the vertical axis.

To achieve animation, we have to alter the box's Y rotation. Ok, let's do it.
First let's try using state, so we need a state variable to hold the Y value:

```tsx
const [y, setY] = useState(0)
```

Then, we need to alter it in the render loop:

```tsx
useBeforeRender(() => {
  setY((oldY) => oldY + 0.1)
})
```

To put everything together, we can create a Functional Component (FC) that wraps
the `box` tag with our new behaviors.

```tsx
import { Vector3 } from '@babylonjs/core/Maths/math.vector'
import React, { FC, useState } from 'react'
import { useBeforeRender } from 'react-babylonjs'

const RotatingBox: FC = () => {
  const [y, setY] = useState(0)
  useBeforeRender(() => {
    setY((oldY) => oldY + 0.1)
  })
  return <box name="box" size={2} position={new Vector3(0, 1, 0)} rotation={new Vector3(0, y, 0)} />
}
```

<code src="./animation/RotatingBox.tsx" />

## Using real-world timing in animations

The rotating box is fun, but it would be nice to control rotation speed in terms
of real-world time (ie: smooth animation). Also, different devices will rotate
different speeds depending on frame rate this way!

Let's adjust the rotation to Revolutions Per Minute (RPM). To do that, we need
to know that one complete revolution of _yaw_ is `Math.PI / 2`.

We also need to know how many milliseconds have passed between animation frames
(since it is not consistent). Fortunately Babylon.js provides a `getDeltaTime()`
that provides that duration. Using all that information, we can do this instead:

```tsx
const RPM = 5
setY((oldY) => oldY + (RPM / 60) * Math.PI * 2 * (deltaTimeInMillis / 1000))
```

## Making `rpm` a component prop

Let's use the power of Typescript to create some spinning box props that accepts
RPM (not needed in JavaScript projects):

```tsx
type RotatingBoxProps = {
  rpm: number
}
```

This will be the props that we pass to the box. Let's update the box component
to use it:

```tsx
const RotatingBox: FC<RotatingBoxProps> = ({ rpm }) => ...
```

And then update the hook:

```tsx
useBeforeRender(() => {
  // ...
  setY((oldY) => oldY + (rpm / 60) * Math.PI * 2 * (deltaTimeInMillis / 1000))
})
```

Now that's a nice reusable component! We use it like this:

```tsx
<RotatingBox rpm={10} />
```

Let's try it. We should see one rotation every 6 seconds when `rpm` is 10
(60/10=6).

<code src="./animation/RPMBox.tsx" />

## Making `rpm` even more reactive

In the interests of completeness, you might notice the hook is referring to
`rpm`. If `rpm` were to change, we would want to make sure that new value took
effect. Therefore, just like `useEffect`, `rpm` is a dependency:

```tsx
useBeforeRender(
  () => {
    // ...
  },
  undefined,
  undefined,
  undefined,
  [rpm]
)
```

You can try it out by choosing the RPM here and seeing that it alters the
rotation speed accordingly.

<code src="./animation/RPMBox3.tsx" />

## Direct object manipulation (not via state)

The state props will flow on the reconciler schedule and changing state in the
render loop can have very noticeable performance implications.

Directly altering Babylon.js object properties via refs bypasses that overhead
and will be a more accurate animation smoothing. Whereas the reconciler will
schedule the updates using it's own algorithm, this method will immediately
apply the update. It should be noted as well that this will not cause re-renders
of the component itself, which was innefficiently creating new Vector3 objects
every render in above examples.

<code src="./animation/NoState.tsx" />

There is also in
Example->Basic->[Animations](../examples/basic/animations.mdx) that
uses an Animation object that can be looped and has easing functions, etc.
